package lupita.controller;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.lucene.document.Document;
import org.apache.lucene.document.Fieldable;
import org.apache.lucene.index.Term;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.MultiPhraseQuery;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.regex.RegexQuery;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.NIOFSDirectory;

import lupita.model.vos.CloudTags;
import lupita.model.vos.FileSystemItem;
import lupita.persistence.MySQLImpl;
import lupita.utils.Page;
import lupita.utils.Paginating;
import lupita.utils.PaginatingImpl;
import lupita.utils.UtilsSearcher;

/**
 * Servlet implementation class SearcherSvt
 */
public class SearcherSvt extends HttpServlet {
private static final int ITEMS_BY_PAGE = 15;
	
	private static final long serialVersionUID = 1L;

	public static final String PATH_INDEX = "/FILES_INDEX";
	private MySQLImpl mysql;
	
	//private TagDAO tagDAO; 

	/**
	 * @see HttpServlet#HttpServlet()
	 */
	public SearcherSvt() {
		super();
		// TODO Auto-generated constructor stub
		// tagDAO = this.daoFactory.getTagDAO();
	}

	/**
	 * @see HttpServlet#service(HttpServletRequest request, HttpServletResponse
	 *      response)
	 */
	protected void service(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		// TODO Auto-generated method stub
		PrintWriter out = response.getWriter();

		String filters = "";
		filters = getSelectedFilters(request, filters);
		// obtiene el texto de busqueda del input de la interfaz de usuario
		
		CloudTags ct = new CloudTags();
		String searchInput = request.getParameter("txtSearchWord");
		List<String> tagsSearch = ct.splitInputTxt(searchInput);
		ct.updateTags(tagsSearch);
		if (tagsSearch.size() == 0) {
			out.println("<script type='text/javascript'>alert('No se permite realizar busquedas vacias');history.go(-1)</script>");
			return;
		}

		HttpSession session = request.getSession();
		ServletContext servletContext = session.getServletContext();
		String indexDir = servletContext.getRealPath(SearcherSvt.PATH_INDEX);
		//String repositoryDir = servletContext.getRealPath(SearcherSvt.PATH_SEARCH);

		List<Object> listResult = new ArrayList<Object>();

		try {
			listResult = search(indexDir, tagsSearch, filters, 1);
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		List<FileSystemItem> listFileRepo = (List<FileSystemItem>)listResult.get(0);
		Paginating paginator = new PaginatingImpl(listFileRepo, ITEMS_BY_PAGE);
		session.removeAttribute("paginator");
		session.setAttribute("paginator", paginator);
		Page pageOne = paginator.getFirstPage();
		session.removeAttribute("currentPage");
		
		session.removeAttribute("fileRepoList");
		List currentFileRepoList = (pageOne == null)?null:pageOne.getContents();
		session.setAttribute("fileRepoList", currentFileRepoList);
		
		Double searchTime = (Double)listResult.get(1);
		if(currentFileRepoList == null || currentFileRepoList.size() == 0){
			request.setAttribute("listFileRepoSize", 0);			
		}else{
			request.setAttribute("listFileRepoSize", listFileRepo.size());
			request.setAttribute("currentPageNumber", pageOne.getPageNum());
			request.setAttribute("totalPage", pageOne.getTotalPage());
			
			request.setAttribute("listFileRepo", currentFileRepoList);
			request.setAttribute("searchTime", searchTime);		
		}
		
		request.setAttribute("search", tagsSearch);
		
		 request.setAttribute("isIndizado", false);
		request.setAttribute("searchedQuery", searchInput);		
		RequestDispatcher requestDispatcher = getServletContext().getRequestDispatcher("/searcher.jsp");
		requestDispatcher.forward(request, response);
		
	}

	private String getSelectedFilters(HttpServletRequest request, String filters) {
		String[] searchFilters = request.getParameterValues("search-filters");
		for (int i = 0; searchFilters != null && i < searchFilters.length; i++) {

			if (searchFilters[i].compareTo(".*[fF][lL][vV]") == 0) {
				request.setAttribute("ckbFLVStatus", "checked");
			}

			if (searchFilters[i].compareTo(".*[mM][pP][3]") == 0) {
				request.setAttribute("ckbMP3Status", "checked");
			}

			if (searchFilters[i].compareTo(".*[dD][oO][cC]|.*[dD][oO][cC][xX]") == 0) {
				request.setAttribute("ckbWordStatus", "checked");
			}

			if (searchFilters[i].compareTo(".*[xX][lL][sS]") == 0) {
				request.setAttribute("ckbExcelStatus", "checked");
			}

			if (searchFilters[i].compareTo(".*[pP][pP][tT]") == 0) {
				request.setAttribute("ckbPPTStatus", "checked");
			}
			if (searchFilters[i].compareTo(".*[tT][xX][tT]") == 0) {
				request.setAttribute("ckbTXTStatus", "checked");
			}

			if (searchFilters[i].compareTo(".*[hH][tT][mM][lL]") == 0) {
				request.setAttribute("ckbHTMLStatus", "checked");
			}

			if (searchFilters[i].compareTo(".*[pP][dD][fF]") == 0) {
				request.setAttribute("ckbPDFStatus", "checked");
			}

			filters += searchFilters[i];
			// Se valida que no es el ultimo elemento de la lista de filtros
			if (i < searchFilters.length - 1) {
				filters += "|";
			}
		}
		if (filters.trim().length() == 0) {
			filters = ".*";
		}
		return filters;
	}

	private static List<Object> search(String indexDir, List<String> qTerms,
			String filters, int pageNum) throws IOException, ParseException {

		Directory dir = NIOFSDirectory.open(new File(indexDir));
		IndexSearcher indexSearcher = new IndexSearcher(dir);

		// terminos para la busqueda en el campo "contents"
		Term[] arrayTerms = UtilsSearcher.getListWords(qTerms, "contents");

		MultiPhraseQuery termsContentsQuery = new MultiPhraseQuery();
		termsContentsQuery.add(arrayTerms);

		// se usan expresiones regulares para filtrar el tipo de archivos
		RegexQuery filtersQuery = new RegexQuery(new Term("filename", filters));

		BooleanQuery query = new BooleanQuery();

		if (!UtilsSearcher.mediaAllFiles(filters)) {
			query.add(termsContentsQuery, BooleanClause.Occur.MUST);
		}

		query.add(filtersQuery, BooleanClause.Occur.MUST);

		// empieza a contarse el tiempo de la busqueda
		double start = System.currentTimeMillis();

		TopDocs hits = indexSearcher.search(query, 10000);

		Document doc;
		FileSystemItem fileRepo;
		List<FileSystemItem> listFileRepo = new ArrayList<FileSystemItem>();

		for (ScoreDoc scoreDoc : hits.scoreDocs) {
			doc = indexSearcher.doc(scoreDoc.doc);

			List<Fieldable> fields = doc.getFields();

			fileRepo = new FileSystemItem();

			for (Fieldable fieldable : fields) {
				String fieldName = fieldable.name();

				if (fieldName.equalsIgnoreCase("filename")) {
					fileRepo.setFileName(doc.get(fieldName));

				} else if (fieldName.equalsIgnoreCase("fullpath")) {
					fileRepo.setFullPath(doc.get(fieldName));

				} else if (fieldName.equalsIgnoreCase("filelength")) {
					Double fileLength = Double.parseDouble(doc.get(fieldName));
					fileRepo.setFileLength(fileLength);

				} else {

					String fieldValue = doc.get(fieldName);

					Map<String, String> mapFields = new HashMap<String, String>();
					mapFields.put(fieldName, fieldValue);

					List<Map<String, String>> fieldsFileRepo = fileRepo
							.getFields();

					fieldsFileRepo.add(mapFields);

					fileRepo.setFields(fieldsFileRepo);

				}

			}

			listFileRepo.add(fileRepo);
		}

		// busqueda personalizada para los archivos multimedia *.flv y *.mp3
		if (UtilsSearcher.mediaAllFiles(filters)) {
			listFileRepo = UtilsSearcher.searchByMediaName(listFileRepo,
					qTerms);

			for (FileSystemItem file : listFileRepo) {
				System.out.println(file.getFileName());
			}
		}

		// se pagina el resultado
		// listFileRepo = SearcherUtils.paginateResult(listFileRepo, pageNum);

		double end = System.currentTimeMillis();

		// se calcula el tiempo de busqueda
		double searchTime = (end - start) / 1000;
		int decimalPlace = 3;
		BigDecimal bd = new BigDecimal(searchTime);
		bd = bd.setScale(decimalPlace, BigDecimal.ROUND_DOWN);
		searchTime = bd.doubleValue();

		// se cierra el indice de la busqueda
		indexSearcher.close();

		// se crea la lista de resultados
		List<Object> listResult = new ArrayList<Object>();
		// primero los archivos resultantes
		listResult.add(listFileRepo);
		// segundo el tiempo de busqueda
		listResult.add(searchTime);
		return listResult;
		
	}

}
